package com.ala4.oxcafe.boot;

import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcelFactory;
import cn.idev.excel.write.metadata.WriteSheet;
import com.ala4.oxcafe.boot.async.AsyncExportService;
import com.ala4.oxcafe.boot.utils.ExcelAopUtil;
import com.ala4.oxcafe.boot.utils.ExcelUtil;
import com.ala4.oxcafe.boot.utils.ResponseUtil;
import com.ala4.oxcafe.common.utils.ResponseWriter;
import com.ala4.oxcafe.common.utils.object.ObjectUtil;
import com.ala4.oxcafe.domain.R;
import com.ala4.oxcafe.export.ExportPage;
import com.ala4.oxcafe.export.ExportResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 导出功能AOP
 *
 * @author PING
 * @version 1.0
 * @date 2025/3/26 10:26
 */
@Slf4j
@Aspect
@Order(10)
@Component
@AllArgsConstructor
public class ExcelExportAop {

    private final AsyncExportService asyncExportService;

    @Pointcut("@annotation(com.ala4.oxcafe.boot.ExcelExport)")
    public void excelExportPointcut() {

    }


    @Around(value = "excelExportPointcut() && @annotation(excelExport)")
    public Object excelExport(ProceedingJoinPoint joinPoint, ExcelExport excelExport) throws Throwable {

        HttpServletResponse response = ResponseUtil.getResponse();

        // 如果有分页信息 那么使用分页导出
        ExportPage pageDomain = ExcelAopUtil.getAopArgsPageRequest(joinPoint);

        if (ObjectUtil.isNotNull(pageDomain)) {
            this.pageExport(response, joinPoint, excelExport);
        } else {

            Object target = joinPoint.getTarget();
            Object[] args = joinPoint.getArgs();
            Method method = ExcelAopUtil.getAopArgsMethod(joinPoint.getSignature());
            List<?> dataList = ExcelUtil.requestDataList(target, method, args);

            // 导出文件
            ExcelUtil.buildOutputExcelSingle(response, excelExport).doWrite(dataList);
        }

        return null;
    }

    private void pageExport(HttpServletResponse response, ProceedingJoinPoint joinPoint, ExcelExport excelExport) throws InvocationTargetException, IllegalAccessException, IOException {


        Object target = joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();
        Method method = ExcelAopUtil.getAopArgsMethod(joinPoint.getSignature());

        ExportPage exportPage = ExcelAopUtil.getAopArgsPageRequest(joinPoint);
        // 每次导出这么多条
        exportPage.setPageSize(excelExport.pageSize());
        exportPage.setSearchCount(true);

        ExportResult<?> exportResult = ExcelUtil.requestDataPage(target, method, args);

        // 小于异步阈值 数据直接 分页导出
        if (exportResult.getDataTotal() <= excelExport.asyncThreshold()) {

            // 第一次查询的数据
            List<?> dataList = exportResult.getRecords();
            // 总页数
            Integer pageTotal = exportResult.getTotalPage();

            ExcelWriter excelWriter = ExcelUtil.buildOutputExcel(response, excelExport);

            try (excelWriter) {
                WriteSheet writeSheet = FastExcelFactory.writerSheet(excelExport.excelName()).build();
                excelWriter.write(dataList, writeSheet); // 写入批次

                int currentPage = exportPage.getPageNum() + 1;
                while (currentPage <= pageTotal) {

                    // 设置页数
                    exportPage.setPageNum(currentPage);
                    // 设置不count
                    exportPage.setSearchCount(false);
                    exportResult = ExcelUtil.requestDataPage(target, method, args);

                    dataList = exportResult.getRecords();
                    excelWriter.write(dataList, writeSheet); // 写入批次
                    currentPage = currentPage + 1;
                }
            }

            excelWriter.finish();

        } else {
            // 判断线程池可不可以继续接受任务
            if (asyncExportService.canAcceptTask()) {
                // 分页异步导出
                asyncExportService.asyncExportAndResponse(target, method, args, exportPage, exportResult, excelExport);
                // 文件正在异步导出中,请到xxx查看
                ResponseWriter.write(response, R.ok("文件正在异步导出中,请到xxx查看"));
            } else {
                // 导出队列已满 请稍后再试
                ResponseWriter.write(response, R.ok("导出队列已满 请稍后再试"));
            }
        }
    }

}
